package com.oxxo.gallery.ftp;

import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Label;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JApplet;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;

import com.oxxo.gallery.exception.MissingParamException;

/**
 * This Applet is used to upload files to an FTP Server. It acts like an FTP
 * client that receives the necessary parameters for the FTP server and the file
 * to upload. <br/>
 * Optionally it has the ability to redirect after succesfully uploaded to
 * another webpage.
 * The applet uses the double-buffering technique to avoid flickering when
 * repainting the applet.
 * <a href="http://www.realapplets.com/tutorial/DoubleBuffering.html">
 * Double-buffering </a>
 * @author Ignacio Marmolejo
 * @version 0.0.1
 */
public class FtpUploadApplet extends JApplet implements CopyStreamListener{

    private String localFile = null;
    private String remoteFile = null;
    private String ftpDir = null;
    private String ftpAddress = null;
    private String ftpUsername = null;
    private String ftpPassword = null;
    private String redirectUrl = null;
    private Logger logger = null;
    private FtpUploadThread uploadThread = null;
    private boolean fileUploaded = false;

    private long fileSize = 0;
    private long totalBytesTransferred = 0;
    private double transferedPercentage = 0.0;
    
    private JProgressBar progressBar = null;

    /**
     * Initialization method that will be called after the applet is loaded into
     * the browser.
     */
    @Override
    public void init() {
        logger = Logger.getLogger(FtpUploadApplet.class.getName());
        logger.log(Level.INFO, "init");

        try {
            loadAppletParameters();
        } catch (MissingParamException mpe) {
            logger.log(Level.SEVERE, mpe.toString());
            System.exit(1);
        }
        
        try {
          SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                createGUI();
            }
          });
        } catch (InterruptedException ie) {
          logger.log(Level.SEVERE, ie.toString());
        }
        catch (InvocationTargetException ite)
        {
          logger.log(Level.SEVERE, ite.toString()); 
        }

        uploadThread = new FtpUploadThread(localFile, remoteFile, ftpAddress, ftpUsername, ftpPassword, ftpDir);
        uploadThread.setListener(this);
        SwingUtilities.invokeLater(uploadThread);
    }

    /**
     * Set the necessary parameters for the application that are passed as
     * params in the html source
     */
    private void loadAppletParameters() throws MissingParamException {
        if ((localFile = getParameter("localFile")) == null) {
            throw new MissingParamException("Missing the localFile param");
        }

        if ((remoteFile = getParameter("remoteFile")) == null) {
            throw new MissingParamException("Missing the remoteFile param");
        }

        if ((ftpDir = getParameter("ftpDir")) == null) {
            throw new MissingParamException("Missing ftpDir param");
        }

        if ((ftpAddress = getParameter("ftpAddress")) == null) {
            throw new MissingParamException("Missing ftpAddress param");
        }

        if ((ftpUsername = getParameter("ftpUsername")) == null) {
            throw new MissingParamException("Missing ftpUsername param");
        }

        if ((ftpPassword = getParameter("ftpPassword")) == null) {
            throw new MissingParamException("Missing ftpPassword param");
        }

        if ((redirectUrl = getParameter("redirectUrl")) == null) {
            // This param is optional
        }
        
        logger.log(Level.INFO, "Local File: "  + localFile);
        logger.log(Level.INFO, "Remote File: "  + remoteFile);
        logger.log(Level.INFO, "FTP Dir: "  + ftpDir);
        logger.log(Level.INFO, "redirect URL: "  + redirectUrl);
    }
    
    private void createGUI() {
      GridLayout mainLayout = new GridLayout(0, 1);
      getContentPane().setLayout(mainLayout);
      
      Label label1 = new Label("Uploading files to the FTP Server");
      Label label2 = new Label("Please Wait");
      progressBar = new JProgressBar();
      progressBar.setIndeterminate(true);
      
      getContentPane().add(label1);
      getContentPane().add(label2);
      getContentPane().add(progressBar);
    }

    /**
     * Shows the percentage transfered by the thread and shows a graphic
     * that updates while the butes are tranfered.<br>
     * These are painted in an Image. Then the image is updated in the applet.
     * This is technique called: 
     * <a href="http://www.realapplets.com/tutorial/DoubleBuffering.html">
     * Double-buffering </a>
     * @param g The graphic where we are going to paint
     */
    @Override
    public void paintComponents(Graphics g){
      super.paintComponents(g);
      progressBar.setIndeterminate(false);
      progressBar.setMaximum((int) fileSize);
      progressBar.setValue((int) totalBytesTransferred);
    }

    /**
     * Event that updates the bytes transfered by the ftp client.
     * @param totalBytesTransferred Total number of bytes transfered
     * @param bytesTransferred Number of byte transfered during these event
     * @param streamSize The size of the buffer being transfered
     */
    public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
        fileSize = streamSize;
        this.totalBytesTransferred = totalBytesTransferred;
        if(this.totalBytesTransferred == streamSize) {
            fileUploaded = true;
        }
        transferedPercentage = ((double)totalBytesTransferred / (double)streamSize) * 100;
        
        repaint();
    }

    public void bytesTransferred(CopyStreamEvent cse) {
        
    }
    
    @Override
    public void stop() {
      logger.log(Level.INFO, "stop");
    }
}
